home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Tools / make-lists / make-lists.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  10.8 KB  |  473 lines

  1. /* make-lists.c: */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Tools/make-lists/RCS/make-lists.c,v 6.0 1991/12/18 20:30:32 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Tools/make-lists/RCS/make-lists.c,v 6.0 1991/12/18 20:30:32 jpo Rel $
  9.  *
  10.  * $Log: make-lists.c,v $
  11.  * Revision 6.0  1991/12/18  20:30:32  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. /*
  19.  * 
  20.  * Reads usernames aliases file, and creates quipu distribution list
  21.  * channel files.
  22.  * 
  23.  * Usage:
  24.  * 
  25.  * make-lists input channel-file list-directory
  26.  * 
  27.  * A line starting with '#' is a comment. Else, a line containg both
  28.  * ':' and ',' is assumed to be the first line of a list; it continues
  29.  * while succeeding lines start with whitespace.
  30.  * 
  31.  * Note that the list directory must be in a form suitable for
  32.  * prefixing directly a filename (ie ends in / on unix, or is like
  33.  * [zxc] or thing: on VMS), this name is placed into the channel-file.
  34.  * 
  35.  * (nb vms/unix compatible, mainly so I can debug with a *decent* debugger.
  36.  * It'll only be run 'in anger' on un*x) (M.A.Scott)
  37.  * 
  38.  * 
  39.  * Modified, fairly extensively A.Macpherson.
  40.  * 
  41.  */
  42.  
  43.  
  44. static char sccsid[] = { "%W%\t-\t%E%\tSTL\n" };
  45.  
  46. #include <stdio.h>
  47.  
  48. extern char    *malloc();
  49. extern char    *realloc();
  50. extern char    *strchr(), *strrchr();
  51. extern char    *strcpy();
  52.  
  53. static int readline ();
  54. static int addusers ();
  55. static void panic ();
  56.  
  57. #define MAXMODERATOR 6
  58. struct list {
  59.   struct list    *next;        /* link pointer */
  60.   struct list    *left;         /* other link */
  61.   char           *list_name;    /* name of the list (eg "200") */
  62.   char           *users;    /* points to '\n' separated record of users */
  63.   int             users_alloc;    /* currently allocated space INCLUDING the
  64.                  * '\0' */
  65.   int             users_used;    /* currently used space including the null */
  66.   char           *moderator[MAXMODERATOR];    /* list-request person(s) */
  67. };
  68.  
  69. #define USERS_INCR 512        /* increment for 'users' area */
  70.  
  71. static struct list *list_pointer;
  72.  
  73. #ifndef BUFSIZ
  74. #    define    BUFSIZ    255        /* input line length allowed */
  75. #endif
  76.  
  77. #ifdef VMS
  78. # define    ERROR    (USER_FATAL|USER_INHIBIT)
  79. # define    OK    USER_SUCCESS
  80. # include    <misc.h>
  81. #else
  82. # define    ERROR    1
  83. # define    OK    0
  84. # define    EOS    '\0'
  85. #endif
  86.  
  87.  
  88. #define FIRST    0
  89. #define CONTIN    1
  90.  
  91. static struct list *get_list();
  92. static void    write_tables();
  93. static int    trim();
  94. static int    analyse_first();
  95. static int    analyse_contin();
  96. static int    analyse_request();
  97.  
  98. static char    *
  99.     mymalloc(n)
  100. int             n;
  101. {
  102.     char           *p = malloc((unsigned) n);
  103.     
  104.     if (p == 0) {
  105.     perror("mymalloc");
  106.     exit(ERROR);
  107.     }
  108.     return p;
  109. }
  110.  
  111. main(argc, argv)
  112. int             argc;
  113. char           *argv[];
  114.  
  115. {
  116.     FILE           *input;
  117.     static char     buffer[BUFSIZ + 1];
  118.     int             state;
  119.     struct list    *current = 0;
  120.     
  121.     if (argc != 4) {
  122.     (void) printf("usage: %s input-file channel-table dislist-directory\n",
  123.               argv[0]);
  124.     exit(ERROR);
  125.     }
  126.     input = fopen(argv[1], "r");
  127.     if (input == 0) {
  128.     perror("cannot read input");
  129.     exit(ERROR);
  130.     }
  131.     /* read entire input file.... */
  132.     state = FIRST;
  133.     
  134.     while (readline(buffer, BUFSIZ, input) != EOF) {
  135.     
  136.     if (buffer[0] == '#' || buffer[0] == '\0')
  137.         continue;            /* comment line */
  138.     
  139.     switch (state) {
  140.     case FIRST:
  141.         if (buffer[0] == ' ') {
  142.         (void) printf("unexpected continuation line - ignored!\n%s\n", buffer);
  143.         continue;
  144.         }
  145.         trim(buffer);
  146.         /*
  147.          * it's not an error if it's not a list, but we need to check for a
  148.          * request line
  149.          */
  150.         if (analyse_request(buffer, current))
  151.         break;
  152.         if (analyse_first(buffer, ¤t))
  153.         state = CONTIN;
  154.         break;
  155.         
  156.     case CONTIN:
  157.         if (!analyse_contin(buffer, current))
  158.         state = FIRST;
  159.         break;
  160.         
  161.     default:
  162.         panic();
  163.         break;
  164.     }
  165.     }
  166.     (void) fclose(input);
  167.     
  168.     write_tables(argv[2], argv[3]);
  169. }
  170.  
  171.  
  172. /* returns 1 if user list end in ',' else 0 */
  173. static int analyse_first(buffer, current_pointer)
  174. char           *buffer;
  175. struct list   **current_pointer;
  176. {
  177.     struct list    *p;
  178.     char           *rest;
  179.     int             i;
  180.     
  181.     /* get dis list name */
  182.     rest = strchr(buffer, ':');
  183.     if (rest == 0)
  184.     panic();
  185.     *rest++ = EOS;
  186.     
  187.     p = get_list(buffer);
  188.     
  189.     *current_pointer = p;
  190.     return addusers(rest, p);    /* and user list */
  191. }
  192.  
  193. /* returns 1 if user list end in ',' else 0 */
  194. static int 
  195.     analyse_contin(buffer, current_pointer)
  196. char           *buffer;
  197. struct list    *current_pointer;
  198. {
  199.     if ((strchr(buffer, ':') != 0) || (buffer[0] != ' ')) {
  200.     (void) printf("continuation line of list expected - ignored!\n%s\n",
  201.               buffer);
  202.     return 0;
  203.     }
  204.     trim(buffer);
  205.     return addusers(buffer, current_pointer);
  206. }
  207.  
  208.  
  209. /*
  210.  * check for a -request, ie moderator, line. This is assumed to occur after
  211.  * the list is defined. Duplicate moderators are appended, up to a maximum.
  212.  */
  213. static 
  214.     analyse_request(buffer, current_pointer)
  215. char           *buffer;
  216. struct list    *current_pointer;
  217. {
  218.     char           *moderator = strchr(buffer, ':');
  219.     char           *dash;
  220.     char           *at;
  221.     struct list    *p = current_pointer;
  222.     int             i;
  223.     
  224.     if (moderator == 0)
  225.     return(0);
  226.     
  227.     *moderator++ = EOS;
  228.     dash = strrchr(buffer, '-');
  229.     if (dash == 0 || strncmp(dash + 1, "request", 7) != 0) {
  230.     *--moderator = ':';
  231.     return(0);
  232.     }
  233.     
  234.     *dash = EOS;            /* buffer now points to list name */
  235.     
  236.     /*
  237.      * good chance current list is the one! If not, scan whole list. 
  238.      */
  239.     if ((p == 0) || strcmp(p->list_name, buffer) != 0)
  240.     p = get_list(buffer);
  241.     
  242.     for (i = 0; i < MAXMODERATOR; ++i) {
  243.     if (dash = strchr(moderator, ','))
  244.         *dash++ = EOS;
  245.     if (p->moderator[i] == 0) 
  246.         p->moderator[i] = mymalloc(strlen(moderator) + 1);
  247.     at = strchr(moderator, '@');
  248.     if (at != 0)
  249.         *at = EOS;
  250.     (void) strcpy(p->moderator[i], moderator);
  251.     if (dash)
  252.         moderator = dash;
  253.     else
  254.         break;
  255.     }
  256.     if (i >= MAXMODERATOR)
  257.     (void) printf("too many moderators for list %s: %s ignored!\n",
  258.               buffer, moderator);
  259.     return(1);
  260. }
  261.  
  262.  
  263. static void 
  264.     write_tables(channel_file, table_dir)
  265. char           *channel_file, *table_dir;
  266. {
  267.     struct list    *p;
  268.     FILE           *fch;
  269.     void            inorder_lists();
  270.     
  271.     fch = fopen(channel_file, "w");
  272.     if (fch == 0) {
  273.     (void) printf("channel file open error\n");
  274.     perror(channel_file);
  275.     exit(ERROR);
  276.     }
  277.     if (chdir(table_dir) != 0) {
  278.     (void) printf("list directory error\n");
  279.     perror(table_dir);
  280.     unlink(channel_file);
  281.     exit(ERROR);
  282.     }
  283.     
  284.     inorder_lists(list_pointer, fch, table_dir);
  285.     
  286.     if (ferror(fch) != 0 || (fclose(fch) != 0)) {
  287.     (void) printf("channel file write error\n");
  288.     perror(channel_file);
  289.     exit(ERROR);
  290.     };
  291. }
  292.  
  293. char    modbuff[BUFSIZ];
  294.  
  295. void
  296.     inorder_lists(p, fch, table_dir)
  297. struct list *p;
  298. FILE        *fch;
  299. char        *table_dir;
  300. {
  301.     FILE *flist;
  302.     int   i;
  303.     
  304.     if (!p)
  305.     return;
  306.     
  307.     inorder_lists(p->next, fch, table_dir);
  308.     
  309.     if (p->moderator[0] || strchr(p->users, '\n') != (char *)0) {
  310.     flist = fopen(p->list_name, "w");
  311.     if (flist == 0) {
  312.         (void) printf("list file open error\n");
  313.         perror(p->list_name);
  314.         exit(ERROR);
  315.     }
  316.     /*
  317.      * there's a bug in printf in VMS C, at least for old versions, for >512
  318.      * chars output at once, so...
  319.      */
  320. #ifdef VMS
  321.     {
  322.     char           *c;
  323.     
  324.     for (c = p->users; *c != EOS; ++c)
  325.         fputc(*c, flist);
  326.     fputc('\n', flist);
  327.     }
  328. #else
  329.     (void) fputs(p->users, flist);
  330.     (void) fputc('\n', flist);
  331. #endif
  332.     if (ferror(flist) != 0 || (fclose(flist) != 0)) {
  333.         (void) printf("list file write error\n");
  334.         perror(p->list_name);
  335.         exit(ERROR);
  336.     }
  337.     
  338.     (void) fprintf(fch, "%s:%s",    /* listname */
  339.                p->list_name,
  340.                p->moderator[0] != 0 ? p->moderator[0]: "postmaster");
  341.     for (i = 1; i < MAXMODERATOR && p->moderator[i] != 0; ++i)
  342.         (void) fprintf(fch, "|%s", p->moderator[i]);
  343.     (void) fprintf(fch, ",file=%s%s,%s\n",
  344.                table_dir, p->list_name, 
  345.                p->list_name);    /* filename, description */
  346.     strcpy(modbuff, p->list_name);
  347.     strcat(modbuff, "-request");
  348.     if ( p->moderator[0] == 0 || strcmp(modbuff, p->moderator[0])) {
  349.         (void) fprintf(fch, "%s-request:postmaster,%s", p->list_name,
  350.                p->moderator[0] != 0 ? p->moderator[0]: "postmaster");
  351.         for (i = 1; i < MAXMODERATOR && p->moderator[i] != 0; ++i)
  352.         (void) fprintf(fch, "|%s", p->moderator[i]);
  353.         (void) fprintf(fch, ",Moderators for list %s\n",
  354.                p->list_name);    /* filename, description */
  355.     }
  356.     }
  357.     inorder_lists(p->left, fch, table_dir);
  358. }
  359.  
  360. /* remove blanks from string in place */
  361. static int 
  362.     trim(s)
  363. char           *s;
  364. {
  365.     char           *t;
  366.     
  367.     for (t = s; *s != EOS; ++s)
  368.     if (*s != ' ' && *s != '\t')
  369.         *t++ = *s;
  370.     *t++ = EOS;
  371.     return;
  372. }
  373.  
  374.  
  375. /* add users to list, converting ',' to '\n',and increasing space as needed */
  376. /* returns 1 if a trailing comma found, else 0 */
  377. static int 
  378.     addusers(users, p)
  379. char           *users;
  380. struct list    *p;
  381. {
  382.     int             l = strlen(users);
  383.     char           *s;
  384.     int             comma;
  385.     
  386.     /* get enough space and some more */
  387.     if (p->users_used + l > p->users_alloc) {
  388.     p->users = realloc(p->users, (unsigned) (p->users_alloc + l + USERS_INCR));
  389.     if (p->users == 0) {
  390.         (void) printf("out of memory!\n");
  391.         exit(ERROR);
  392.     }
  393.     p->users_alloc += (l + USERS_INCR);
  394.     }
  395.     /* copy across list */
  396.     comma = 0;
  397.     for (s = p->users + p->users_used - 1; *users != EOS; ++s, ++users)
  398.     if (comma = (*users == ','))
  399.         *s = '\n';
  400.     else
  401.         *s = *users;
  402.     
  403.     p->users_used += l;
  404.     
  405.     return comma;
  406. }
  407.  
  408.  
  409. static int 
  410.     readline(buffer, len, input)
  411. char           *buffer;
  412. int             len;
  413. FILE           *input;
  414. {
  415.     int             i;
  416.     
  417.     if (fgets(buffer, len, input) == 0) {
  418.     if (!feof(input)) {
  419.         perror("read error");
  420.         exit(ERROR);
  421.     } else
  422.         return EOF;
  423.     }
  424.     i = strlen(buffer);
  425.     if (buffer[i - 1] != '\n')
  426.     (void) printf("line too long (data may be lost):\n%s\n", buffer);
  427.     else
  428.     buffer[i - 1] = EOS;
  429.     return 0;
  430. }
  431.  
  432.  
  433. static void panic()
  434. {
  435.     (void) printf("internal error!!\n");
  436.     exit(ERROR);
  437. }
  438.  
  439. static struct list *
  440.     get_list(name)
  441. char *name;
  442. {
  443.     register struct list **p;
  444.     int           lr;
  445.     
  446.     /* Double de-reference so only one pointer needed, and
  447.        the empty tree is not a special case */
  448.     
  449.     for (p = &list_pointer; *p != 0; ) {
  450.     if ((lr = strcmp((*p)->list_name, name)) == 0){
  451.         return(*p);
  452.     }
  453.     p = (lr > 0) ? &(*p)->next : &(*p)->left;
  454.     }
  455.     
  456.     /* grab some store and init it... */
  457.     *p = (struct list *) mymalloc(sizeof(struct list));
  458.     
  459.     (*p)->users = mymalloc(USERS_INCR + 1);
  460.     (*p)->users[0] = EOS;
  461.     (*p)->users_alloc = USERS_INCR + 1;
  462.     (*p)->users_used = 1;        /* the EOS */
  463.     for (lr = 0; lr < MAXMODERATOR; ++lr)
  464.     (*p)->moderator[lr] = 0;
  465.     
  466.     (*p)->next = (struct list *) 0;
  467.     (*p)->left = (struct list *) 0;
  468.     
  469.     (*p)->list_name = mymalloc(strlen(name) + 1);
  470.     (void) strcpy((*p)->list_name, name);    /* copy list name */
  471.     return (*p);    
  472. }
  473.